﻿/**
 * \file CMemory.h
 * \reversion 0.1
 * \brief 动态内存池，应用于大内存分配的动态内存池
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __CMEMORY__H
#define __CMEMORY__H

#include "CStaticMemPool.h"
#include "CDynMemPool.h"

//////////////////////////////////////////////////////////////////////////////////////////////
/// 内存分配接口说明：
///		该接口使用了内存池来加速内存分配速度和减少内存碎片的出现，使用
/// 时请遵守以下规则：
///		1.如果要使用std容器，请使用CPoolAlloc分配器，因为这个分配器
/// 使用内存池分配和销毁内存块。
///		2.类似std::vector这种内存是连续的容器，如果内存大于128字节后，
/// 内存池对它的作用降低到0，所以请不要大量使用vector频繁分配销毁较大
/// 内存块。
///		3.如果程序中对一种对象频繁创建和销毁，请把该对象注册进入动态
/// 内存池CDynMemPool中，以便于使用内存池方式分配与销毁此类型的对象。
///		4.如果你需要使用std::map，std::list这类内存块非连续性的容器时，
/// 请注意，不要把大量的大对象作为元素存放在容器中，该大小应该不大于
/// 100个字节，否则内存池可能分配不了该大小的内存块。尽量把对象的指针
/// 或对象的可快速索引放入容器中，因为指针在32位系统中只占4个字节内存，
/// 我们可以保证使用内存池，充分提高你程序的效率。
///		5.不要把程序中存在较少的大对象注册入CDynMemPool内存池中，因为这
/// 可能会浪费内存，使少量的对象占用大量的内存的现象。
///		6.了解本内存池的实现原理和实现策略大大有力于你更好的使用该内存
/// 池。
///////////////////////////////////////////////////////////////////////////////////////////////

/**
 * \brief 构造对象
 * \param _Ptr：对象地址
 */
template <typename _Ty>
static void s_Construct(_Ty* _Ptr)
{
	/// 构造
	::new (_Ptr) _Ty();
}

/**
 * \brief 构造对象
 * \param _Ptr：对象地址
 * \param _Val：拷贝构造值
 */
template <typename _Ty>
static void s_Construct(_Ty* _Ptr, const _Ty& _Val)
{
	/// 拷贝构造
	::new (_Ptr) _Ty(_Val);
}

/**
 * \brief 析构对象
 * \param _Ptr：对象地址
 */
template <typename _Ty>
static void s_Destroy(_Ty* _Ptr)
{
	/// 析构
	_Ptr->~_Ty();
}

/**
 * \brief 内存分配
 * \param _Count：对象个数
 * \return 分配内存的首地址
 */
template <typename _Ty>
static _Ty* s_Allocate(size_t _Count = 1)
{
	size_t Size = sizeof(_Ty) * _Count;
	if(Size <= CStaticMemPool::__MAX_BYTES_)
	{
		/// 静态大小的小对象内存池
		return static_cast<_Ty*>(CStaticMemPool::GetInstance().Allocate(Size));
	}
	else
	{
		if(CDynMemPool::GetInstance().CanAlloc(Size))
		{
			/// 动态大小的注册大对象内存池
			return static_cast<_Ty*>(CDynMemPool::GetInstance().Allocate(Size));
		}
		else
		{
			/// 向操作系统内核申请内存空间
			return static_cast<_Ty*>(::operator new(Size));
		}
	}
}

/**
 * \brief 内存释放动作
 * \param _Ptr：对象地址
 * \param _Count：对象个数
 * \return 释放是否成功
 */
template <typename _Ty>
static bool s_Deallocate(_Ty* _Ptr, size_t _Count = 1)
{
	size_t Size = sizeof(_Ty) * _Count;
	if(Size <= CStaticMemPool::__MAX_BYTES_)
	{
		/// 释放内存到静态小对象内存池
		return CStaticMemPool::GetInstance().Deallocate(_Ptr, Size);
	}
	else
	{
		if(CDynMemPool::GetInstance().CanAlloc(Size))
		{
			/// 释放内存到动态大小的注册大对象内存池
			return CDynMemPool::GetInstance().Deallocate(_Ptr, Size);
		}
		else
		{
			/// 释放内存到操作系统内核
			::operator delete(_Ptr);

			return true;
		}
	}
}

#endif	/// __CMEMORY__H